//
//  ViewController.m
//  Regatta Mapping
//
//  Created by Asif on 8/4/12.
//  Copyright (c) 2012 TopOfStack Software. All rights reserved.
//

#import "ViewController.h"

#define maptype [[NSUserDefaults standardUserDefaults] integerForKey:@"MapType"]

#define METERS_PER_MILE 1609.344



@implementation ViewController

@synthesize myMapView, chatView, regattaDictionary, raceDictionary, boatDictionary;
@synthesize raceLimitPolygon, raceLimitPolygonView, inputStream, outputStream;
@synthesize serverReturnedData, markAnnotationArray, raceLimitAnnotationArray, racingBoatsArray;
@synthesize raceBoatAnnotationDictionary;

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    //initializing mapView property
    //[myMapView setMapType:MKMapTypeHybrid];
    
    switch (maptype) 
    {
        case 0:
        {
            [myMapView setMapType:MKMapTypeHybrid];
            //[myMapView reloadInputViews];
            break;
        }
        case 1:
        {
            [myMapView setMapType:MKMapTypeSatellite];
            break;
        }
        case 2:
        {
            [myMapView setMapType:MKMapTypeStandard];
            break;
        }
            
        default:
            break;
    }

    
    [myMapView setDelegate:self];
    
    
    markAnnotationArray = [[NSMutableArray alloc] init];
    raceLimitAnnotationArray = [[NSMutableArray alloc] init];
    
    racingBoatsArray = [[NSMutableArray alloc] init];
    raceBoatAnnotationDictionary = [[NSMutableDictionary alloc] init];
    
    /*
    MKCoordinateRegion region = {{0.0, 0.0}, {0.0, 0.0}};
    region.center.latitude = 39.488;
    region.center.longitude = -96.2805;
    region.span.latitudeDelta = 75.01f;
    region.span.latitudeDelta = 75.01f;
    
    [myMapView setRegion:region animated:YES];
     */    
    
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    

        
    /*
    /////// setting the map based on a zoomlocation as the center (from Regatta.xml) /////
    CLLocationCoordinate2D zoomLocation;
    
    zoomLocation.latitude = [[[[regattaDictionary objectForKey:@"RegattaConfig"] objectForKey:@"CentralLatitude"] objectForKey:@"element"] doubleValue];
    zoomLocation.longitude = [[[[regattaDictionary objectForKey:@"RegattaConfig"] objectForKey:@"CentralLongitude"] objectForKey:@"element"] doubleValue];
    
    //NSLog(@"zoomlocation: (%f, %f)", zoomLocation.latitude, zoomLocation.longitude);
    
    //zoomLocation.latitude = 45.425729; //from regatta.xml -> CentralLatitude
    //zoomLocation.longitude= 12.381966; //from regatta.xml -> CentralLongitude
    
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 1*METERS_PER_MILE, 1.333*METERS_PER_MILE);
    
    
    MKCoordinateRegion adjustedRegion = [myMapView regionThatFits:viewRegion];                
    
    [myMapView setRegion:adjustedRegion animated:YES]; 
     */
    
   
    
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    //return YES;
    
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}


-(IBAction)clearChatWindow
{
    chatView.text = @"";
}

-(void) updateChatWindow:(NSString*) chatText
{
    
    NSString* prevString = [NSString stringWithString:chatView.text];
    NSMutableString* newString = [NSMutableString stringWithFormat:@"%@\n", chatText];
    
    [newString appendString:prevString]; 
    
    chatView.text = newString;
    
}


-(IBAction)loadSettings
{
    
    settingView* dropDown = [[settingView alloc] initWithNibName:@"settingView" bundle:nil];
    dropDown.vCont = self;
    
    pop = nil;
    pop = [[[UIPopoverController alloc] initWithContentViewController:dropDown] retain];
    pop.delegate = self;
    
    [pop presentPopoverFromRect:CGRectMake(36, 45, 1, 1) 
                         inView:self.view 
       permittedArrowDirections:UIPopoverArrowDirectionUp 
                       animated:YES];
    
    [dropDown release];
    
}


-(IBAction)loadCategory
{
    Category* anotherDropDown = [[Category alloc] initWithNibName:@"Category" bundle:nil];
    anotherDropDown.vCont2 = self;
    
    pop2 = nil;
    pop2 = [[[UIPopoverController alloc] initWithContentViewController:anotherDropDown] retain];
    pop2.delegate = self;
    
    [pop2 presentPopoverFromRect:CGRectMake(960, 45, 1, 1) 
                          inView:self.view 
        permittedArrowDirections:UIPopoverArrowDirectionUp 
                        animated:YES];
    
    [anotherDropDown release];
}



-(IBAction)zoomIn
{
    ////NSLog(@"Zoom - IN");
    MKCoordinateRegion region;
    //Set Zoom level using Span
    MKCoordinateSpan span;  
    region.center=myMapView.region.center;
    
    span.latitudeDelta=myMapView.region.span.latitudeDelta /2;
    span.longitudeDelta=myMapView.region.span.longitudeDelta /2;
    region.span=span;
    [myMapView setRegion:region animated:TRUE];
}

-(IBAction)zoomOut
{
    MKCoordinateRegion region;
    //Set Zoom level using Span
    MKCoordinateSpan span;  
    region.center=myMapView.region.center;
    span.latitudeDelta=myMapView.region.span.latitudeDelta *1.5;
    span.longitudeDelta=myMapView.region.span.longitudeDelta *1.5;
    region.span=span;
    [myMapView setRegion:region animated:TRUE];
}

-(void) setupMap
{
    ///Compound Mark Annotations BEGIN //////
    
    
    //[myMapView willChangeValueForKey:@"MarkBoatLocation"];
    
    ////NSLog(@"markAnnotationArray contents before: %@", [markAnnotationArray description]);
    
    if([markAnnotationArray count] > 0)
    {
        ////NSLog(@"entering if");
        [myMapView removeAnnotations:markAnnotationArray];
        [markAnnotationArray removeAllObjects];
        
        ////NSLog(@"markAnnotationArray contents after removing all: %@", [markAnnotationArray description]);
    }
    
    
    NSArray* compoundMark = [[[raceDictionary objectForKey:@"Race"] objectForKey:@"Course"] objectForKey:@"CompoundMark"];
    
    ////NSLog(@"compoundmark array: %@", [compoundMark description]);
    
    
    for(int i=0; i<[compoundMark count]; i++)
    {
        id Mark = [[compoundMark objectAtIndex:i] objectForKey:@"Mark"];
        
        NSString* markName = [[compoundMark objectAtIndex:i] objectForKey:@"Name"];
        
        if([Mark isKindOfClass:[NSDictionary class]])
        {
            ////NSLog(@"CompooundMark[%d] has Mark as Dictionary",i);
            
            double latitude = [[Mark objectForKey:@"TargetLat"] doubleValue];
            double longitude = [[Mark objectForKey:@"TargetLng"] doubleValue];
            NSString* name = [Mark objectForKey:@"Name"];
            int sourceID = [[Mark objectForKey:@"SourceID"] intValue];
            
            ////NSLog(@"%@ with sourceID: %d is at (%f, %f)", name, sourceID, latitude, longitude);
            
            CLLocationCoordinate2D markBoatCoord = CLLocationCoordinate2DMake(latitude, longitude);
            
            //custom annotation
            MarkBoatLocation* markBoatAnnotation = [[MarkBoatLocation alloc] 
                                                    initWithName:markName 
                                                    sourceID:[NSString stringWithFormat:@"%@ (%d)",name, sourceID] 
                                                    coordinate:markBoatCoord];
            
            
            
            [myMapView addAnnotation:markBoatAnnotation];
            
            [markAnnotationArray addObject:markBoatAnnotation]; //adding to annotation array
            
            [markBoatAnnotation release];
        }
        
        else if([Mark isKindOfClass:[NSArray class]])
        {
            ////NSLog(@"CompooundMark[%d] has Mark as Array",i);
            
            for(int j=0; j< [Mark count]; j++)
            {
                double latitude = [[[Mark objectAtIndex:j] objectForKey:@"TargetLat"] doubleValue];
                double longitude = [[[Mark objectAtIndex:j] objectForKey:@"TargetLng"] doubleValue];
                NSString* name = [[Mark objectAtIndex:j] objectForKey:@"Name"];
                int sourceID = [[[Mark objectAtIndex:j] objectForKey:@"SourceID"] intValue];
                
                ////NSLog(@"%@ with sourceID: %d is at (%f, %f)", name, sourceID, latitude, longitude);
                
                CLLocationCoordinate2D markBoatCoord = CLLocationCoordinate2DMake(latitude, longitude);
                
                //custom annotation
                MarkBoatLocation* markBoatAnnotation = [[MarkBoatLocation alloc] 
                                                        initWithName:markName 
                                                        sourceID:[NSString stringWithFormat:@"%@ (%d)", name, sourceID] 
                                                        coordinate:markBoatCoord];
                
                [myMapView addAnnotation:markBoatAnnotation];
                
                [markAnnotationArray addObject:markBoatAnnotation];
                
                [markBoatAnnotation release];
                
            }
        }
    }
    
    ////NSLog(@"markAnnotationArray contents after: %@", [markAnnotationArray description]);
    
    //[myMapView didChangeValueForKey:@"MarkBoatLocation"];
    
    //Compound Mark Asnnotations END /////
    
    //// race limit annotations BEGIN ////
    
    //[myMapView willChangeValueForKey:@"RaceLimitLocation"];
    
    //NSLog(@"raceLimitAnnotationArray contents before: %@", [raceLimitAnnotationArray description]);
    
    if([raceLimitAnnotationArray count] > 0)
    {
        //NSLog(@"entering if");
        [myMapView removeAnnotations:raceLimitAnnotationArray];
        [raceLimitAnnotationArray removeAllObjects];
        
        //NSLog(@"raceLimitAnnotationArray contents after removing all: %@", [raceLimitAnnotationArray description]);
    }
    
    NSArray* raceLimit = [[[raceDictionary objectForKey:@"Race"] objectForKey:@"CourseLimit"] objectForKey:@"Limit"];

    
    
    for (NSDictionary* row in raceLimit)
    {
        double latitude = [[row objectForKey:@"Lat"] doubleValue];
        double longitude = [[row objectForKey:@"Lon"] doubleValue];
        NSString* limitSequence = [row objectForKey:@"SeqID"];
        
        ////NSLog(@"raceLimit(%f, %f), %@", latitude, longitude, limitSequence);
        
        CLLocationCoordinate2D limitCoord;
        limitCoord.latitude = latitude;
        limitCoord.longitude = longitude;
        
        //custom annotation
        RaceLimitLocation* raceLimitAnnotation = [[RaceLimitLocation alloc] initWithTitle:limitSequence coordinate:limitCoord];
        
        [myMapView addAnnotation:raceLimitAnnotation];
        
        [raceLimitAnnotationArray addObject:raceLimitAnnotation];
        
        [raceLimitAnnotation release];
        
    }    
    
    //NSLog(@"raceLimitAnnotationArray contents after: %@", [raceLimitAnnotationArray description]);
    
    //// race limit annotations END ////
    
    //// race boundary polygon BEGIN ////
    
    // while we create the route points, we will also be calculating the bounding box of our route
	// so we can easily zoom in on it. 
    
    //NSLog(@"raceLimitPolygon before: %@", [raceLimitPolygon description]);
    if(self.raceLimitPolygon != nil)
    {
        
        [self.myMapView removeOverlay:self.raceLimitPolygon]; //removing boundary with previous coords
    
        self.raceLimitPolygon = nil;
        
        //NSLog(@"inside if: raceLimitPolygon: %@", [raceLimitPolygon description]);
    }
    
	MKMapPoint northEastPoint; 
	MKMapPoint southWestPoint; 
	
	// create a c array of points. 
	MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * raceLimit.count);
    
    for(int idx = 0; idx < raceLimit.count; idx++)
    {
        double latitude = [[[raceLimit objectAtIndex:idx] objectForKey:@"Lat"] doubleValue];
        double longitude = [[[raceLimit objectAtIndex:idx] objectForKey:@"Lon"] doubleValue];
        
        CLLocationCoordinate2D limitCoord;
        limitCoord.latitude = latitude;
        limitCoord.longitude = longitude;
        
        MKMapPoint point = MKMapPointForCoordinate(limitCoord);
        
        //
		// adjust the bounding box
		//
		
		// if it is the first point, just use them, since we have nothing to compare to yet. 
		if (idx == 0) 
        {
			northEastPoint = point;
			southWestPoint = point;
		}
		else 
		{
			if (point.x > northEastPoint.x) 
				northEastPoint.x = point.x;
			if(point.y > northEastPoint.y)
				northEastPoint.y = point.y;
			if (point.x < southWestPoint.x) 
				southWestPoint.x = point.x;
			if (point.y < southWestPoint.y) 
				southWestPoint.y = point.y;
		}
        
		pointArr[idx] = point;
        
    }

    // create the polyline based on the array of points. 
	//self.routeLine = [MKPolyline polylineWithPoints:pointArr count:raceLimit.count];
    self.raceLimitPolygon = [MKPolygon polygonWithPoints:pointArr count:raceLimit.count];
    
    //MKMapRectMake(<#double x#>, <#double y#>, <#double width#>, <#double height#>)
	routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
    
	// clear the memory allocated earlier for the points
	free(pointArr);
    
    // add the overlay to the map
    /*
     if (self.routeLine !=nil) 
     {
     [self.myMapView addOverlay:self.routeLine];
     }
     */
    if(self.raceLimitPolygon != nil)
    {
        [self.myMapView addOverlay:self.raceLimitPolygon];
    }
    
    //NSLog(@"raceLimitPolygon after: %@", [raceLimitPolygon description]);
    
    //zooming on the race course
    
    MKCoordinateRegion region = MKCoordinateRegionForMapRect(routeRect);
    
    //NSLog(@"region's center: %f, %f", region.center.latitude, region.center.longitude);
    
    // MKCoordinateRegionMakeWithDistance(<#CLLocationCoordinate2D centerCoordinate#>, <#CLLocationDistance latitudinalMeters#>, <#CLLocationDistance longitudinalMeters#>)
    
    region = MKCoordinateRegionMakeWithDistance(region.center, 1*METERS_PER_MILE, 1.33*METERS_PER_MILE);
    
    MKCoordinateRegion adjustedRegion = [myMapView regionThatFits:region];
    
    [myMapView setRegion:adjustedRegion animated:YES]; 
    
    //[myMapView didChangeValueForKey:@"RaceLimitLocation"];
    
    
    //// race boundary polygon END ////

}

//Establish socket connection
-(void) initNetWorkCommunicationWithIP:(NSString*)IP Port:(int) port
{
    //NSLog(@"IP: %@, Port: %i", IP, port);
    
    if([pop isPopoverVisible])
    {
        [pop dismissPopoverAnimated:YES];
        pop = nil;
    }
    
    messageHeader = [[NSMutableData alloc] init];
    messageBody = [[NSMutableData alloc] init] ;
    messageCRC = [[NSMutableData alloc] init] ;
    expecting = 0;
    needMore = 15;
    
    //1
	CFReadStreamRef readStream;
	CFWriteStreamRef writeStream;
    
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)IP, port, &readStream, &writeStream);
    
	//2
	inputStream = (__bridge_transfer NSInputStream*)readStream;
	outputStream = (__bridge_transfer NSOutputStream*)writeStream;
    
    //3
	[inputStream setDelegate:self];
	[outputStream setDelegate:self];
    
    //4
	[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
	[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    //5
	[inputStream open];
	[outputStream open];

}

#pragma mark NSStream Delegate methods

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent 
{
	switch (streamEvent) 
    {
			
		case NSStreamEventOpenCompleted: //1
			//NSLog(@"Stream opened");
			break;
		case NSStreamEventHasBytesAvailable: //2
            
			if (aStream == inputStream) 
            {
                /*
                if(reconnectTimer != nil)
                {
                    [reconnectTimer invalidate];
                    reconnectTimer = nil;
                }
                 */
        
				uint8_t buffer[1024*100];
				int len;
				while ([inputStream hasBytesAvailable]) 
                {
                    len = [inputStream read:buffer maxLength:needMore];
                    
                    serverReturnedData = [NSMutableData dataWithBytes:buffer length:len];
                    if(needMore > len)
                    {
                        needMore -= len;
                    }
                    else
                    {
                        needMore = 0;
                    }
                    
                    message_header *h; //declaring message header
                    unsigned char header[15];
                    
                    
                    
                    if(expecting == 0)
                    {
                        [messageHeader appendData:serverReturnedData];
                        if(needMore == 0)
                        {
                            //header received. Now need to receive body
                            expecting = 1;
                            
                            
                            [messageHeader getBytes:header length:15];
                            h = (message_header *)header;
                            needMore = 256*header[14] + header[13];
                            [messageBody setLength:0];
                        }
                    }
                    else if(expecting == 1)
                    {
                        [messageBody appendData:serverReturnedData];
                        if(needMore == 0)
                        {
                            //body received. Now need to receive header
                            expecting = 2;
                            
                            needMore = 4;
                            [messageCRC setLength:0];
                            
                            //NSString* output = [[NSString alloc] initWithData:(NSData*)messageBody encoding:NSASCIIStringEncoding];
                            
                            ////NSLog(@"output: %@", output);
                        }
                    }
                    else if(expecting == 2)
                    {
                        [messageCRC appendData:serverReturnedData];
                        if(needMore == 0)
                        {
                            
                            
                            
                            //========
                            
                            //NSString* output = [[NSString alloc] initWithData:messageBody encoding:NSASCIIStringEncoding];
                            
                            
                            if(h->message_type == 1)
                            {
                                //NSLog(@"Heartbeat");
                                
                                //NSLog(@"header length: %d", messageHeader.length);
                                //NSLog(@"messageBody length: %d", messageBody.length);
                                
                                //unsigned char heartbit[4];
                                //[messageBody getBytes:heartbit length:4];
                                
                                UInt32 theInteger;
                                [messageBody getBytes:&theInteger length:sizeof(theInteger)];
                                
                                if(theInteger>0 && theInteger<500000)
                                {
                                    //NSLog(@"heartbit: %lu", theInteger);
                                }
                                
                                //NSRange range = NSMakeRange(0, 4);
                                
                                // NSString* heartBitText = [[NSString alloc] initWithData:messageBody encoding:NSASCIIStringEncoding];
                                
                                ////NSLog(@"heartbit: %@", heartBitText);
                                
                                //[heartBitText release];
                                
                                ////NSLog(@"crc length: %d",messageCRC.length);
                            }
                            else if(h->message_type == 12){
                                //NSLog(@"Race Status");
                            }
                            else if(h->message_type == 20){
                                //NSLog(@"Display Text Message:");
                                
                                ////NSLog(@"header length: %d", messageHeader.length);
                                ////NSLog(@"messageBody length: %d", messageBody.length);
                                //NSString* output = [[NSString alloc] initWithData:(NSData*)messageBody encoding:NSASCIIStringEncoding];
                                ////NSLog(@"Display txt msg message body: %@", output);
                                ////NSLog(@"crc length: %d",messageCRC.length);
                            }
                            else if(h->message_type == 26){
                                //NSLog(@"XML Message");
                                
                                
                                //code by erfan bhai
                                
                                /*
                                 unsigned char xml_header[14];
                                 [messageBody getBytes:xml_header length:14];
                                 //unsigned char xml_subtype = xml_header[9];
                                 int xml_length = 256*xml_header[13] + xml_header[12];
                                 
                                 NSRange range = {14, xml_length};
                                 NSString *xml_text = [[NSString alloc] initWithData:[messageBody subdataWithRange:range] 
                                 encoding:NSASCIIStringEncoding];
                                 */
                                
                                NSMutableData* xmlMsgData = (NSMutableData*)[messageBody subdataWithRange:NSMakeRange(14, messageBody.length-14)];
                                
                                NSString *xml_text = [[NSString alloc] initWithData:xmlMsgData 
                                                                           encoding:NSUTF8StringEncoding];
                                
                                NSMutableData* XmlMsgSubTypeData = (NSMutableData*)[messageBody subdataWithRange:NSMakeRange(9, 1)];
                                int XmlMsgSubType;
                                [XmlMsgSubTypeData getBytes:&XmlMsgSubType length:1];
                                
                                //NSLog(@"XML type: %d", XmlMsgSubType);
                                
                                //making sure that no extra/illegal char. remains after the final closing tag
                                while (![xml_text hasSuffix:@">"]) 
                                {
                                    xml_text = [xml_text substringToIndex:[xml_text length]-1];
                                }
                                
                                //NSLog(@"XML: %@", xml_text);
                                
                                if(XmlMsgSubType == 5) //Regatta.xml
                                {
                                    regattaDictionary = [XMLReader dictionaryForXMLString:xml_text error:nil];
                                    
                                    //NSLog(@"regatta dictionary: %@", [regattaDictionary description]);
                                }
                                else if(XmlMsgSubType == 6) //Race.xml
                                {
                                    raceDictionary = [XMLReader dictionaryForXMLString:xml_text error:nil];
                                    
                                    //setting up mapview to the race course!
                                    [self setupMap];
                                    
                                    //NSLog(@"race dictionary: %@", [raceDictionary description]);
                                }
                                else if(XmlMsgSubType == 7) //Boats.xml
                                {
                                    //clearing race boats annotations related to
                                    //previous version of Boats.xml
                                    
                                    if(raceBoatAnnotationDictionary != NULL)
                                    {
                                        NSArray* keyArray = [raceBoatAnnotationDictionary allKeys];
                                        
                                        for(int i=0; i<[keyArray count]; i++)
                                        {
                                            [self.myMapView removeAnnotation:[raceBoatAnnotationDictionary objectForKey:[keyArray objectAtIndex:i]]];
                                        }
                                        
                                        [raceBoatAnnotationDictionary removeAllObjects];
                                    }
                                    
                                    
                                    
                                    boatDictionary = [XMLReader dictionaryForXMLString:xml_text error:nil];
                                    
                                    //NSLog(@"Boats dictionary: %@", [boatDictionary description]);
                                    
                                    
                                    //getting all boats
                                    NSArray* allBoatsArray = [[[boatDictionary objectForKey:@"BoatConfig"] objectForKey:@"Boats"] objectForKey:@"Boat"];
                                    
                                    //extracting only race boats 
                                    for(int i=0; i<[allBoatsArray count]; i++)
                                    {
                                        NSDictionary* aBoat = [allBoatsArray objectAtIndex:i];
                                        
                                        if([[aBoat objectForKey:@"Type"] isEqualToString:@"Yacht"])
                                        {
                                            [racingBoatsArray addObject:aBoat];
                                        }
                                    }
                                    
                                    //NSLog(@"racingBoatsArray: %@", [racingBoatsArray description]);
                                    
                                    //assigning annotation object to each race boat
                                    for(int i; i< [racingBoatsArray count]; i++)
                                    {
                                        NSString* sourceID = [[racingBoatsArray objectAtIndex:i] objectForKey:@"SourceID"];
                                        NSString* country = [[racingBoatsArray objectAtIndex:i] objectForKey:@"Country"];
                                        NSString* boatName = [[racingBoatsArray objectAtIndex:i] objectForKey:@"BoatName"];
                                        NSString* stoweName = [[racingBoatsArray objectAtIndex:i] objectForKey:@"StoweName"];
                                        
                                        ////NSLog(@"%@ (%@), %@, %@", boatName, sourceID, stoweName, country);
                                        
                                        RaceBoatAnnotation* raceBoat = [[RaceBoatAnnotation alloc] initWithName:boatName subtitle:[NSString stringWithFormat:@"StoweName: %@, Country: %@, ID: %@", stoweName, country, sourceID] ];
                                        
                                        [raceBoatAnnotationDictionary setObject:raceBoat forKey:sourceID];
                                        
                                        [raceBoat release];
                                    }
                                    
                                    //NSLog(@"raceBoatAnnotationDictionary contents: %@", [raceBoatAnnotationDictionary description] );
                                    
                                }
                                
                                //[xml_text release];
                                
                            }
                            else if(h->message_type == 27){
                                //NSLog(@"Race start status");
                            }
                            else if(h->message_type == 29)
                            {
                                //NSLog(@"Yatch Event Code");
                            }
                            else if(h->message_type == 36)
                            {
                                //NSLog(@"Chatter Text");
                                //NSLog(@"chatterTextBody length: %d", messageBody.length);
                                
                                NSMutableData* chatterTextData = (NSMutableData*)[messageBody subdataWithRange:NSMakeRange(3, messageBody.length-3)];
                                
                                NSString* chatter_text = [[NSString alloc] initWithData:chatterTextData encoding:NSUTF8StringEncoding];
                                
                                //NSLog(@"Chatter text contents: %@", chatter_text);
                                
                                [self updateChatWindow:chatter_text];
                                
                                [chatter_text release];
                                
                            }
                            else if(h->message_type == 37)
                            {
                                //NSLog(@"Boat Location");
                                
                                NSMutableData* boatIDData = (NSMutableData*)[messageBody subdataWithRange:NSMakeRange(7, 4)];
                                
                                NSMutableData* deviceTypeData = (NSMutableData*)[messageBody subdataWithRange:NSMakeRange(15, 1)];
                                
                                NSMutableData* boatLocationLatData = (NSMutableData*) [messageBody subdataWithRange:NSMakeRange(16, 4)];
                                
                                NSMutableData* boatLocationLonData = (NSMutableData*) [messageBody subdataWithRange:NSMakeRange(20, 4)];
                                
                                int DeviceType;
                                [deviceTypeData getBytes:&DeviceType length:1];
                                
                                UInt32 BoatID;
                                [boatIDData getBytes:&BoatID length:sizeof(boatIDData)];
                                
                                SInt32 boatLat;
                                [boatLocationLatData getBytes:&boatLat length:sizeof(boatLocationLatData)];
                                
                                //converting binary latitude to floating value
                                double boatLatitude = (double) boatLat*180.0/
                                2147483648.0;
                                
                                SInt32 boatLon;
                                [boatLocationLonData getBytes:&boatLon length:sizeof(boatLocationLonData)];
                                
                                double boatLongitude = (double) boatLon*180.0/ 2147483648.0;
                                
                                //NSLog(@"boatID: %lu, deviceType: %d, lat: %f, lon: %f", BoatID, DeviceType, boatLatitude, boatLongitude);
                                
                                if(DeviceType == 1) //Race yacht
                                {
                                    CLLocationCoordinate2D boatLocCord = CLLocationCoordinate2DMake(boatLatitude, boatLongitude);
                                    
                                    [[raceBoatAnnotationDictionary objectForKey:[NSString stringWithFormat:@"%lu", BoatID] ] setCoordinate:boatLocCord];
                                    
                                    [myMapView addAnnotation:[raceBoatAnnotationDictionary objectForKey:[NSString stringWithFormat:@"%lu", BoatID]] ];
                                }
                                
                            }
                            else if(h->message_type == 38)
                            {
                                //NSLog(@"Mark Rounding");
                            }
                            else if(h->message_type == 44){
                                //NSLog(@"Course Wind");
                                
                                ////NSLog(@"header length: %d", messageHeader.length);
                                ////NSLog(@"messageBody length: %d", messageBody.length);
                                //NSString* output = [[NSString alloc] initWithData:(NSData*)messageBody encoding:NSASCIIStringEncoding];
                                ////NSLog(@"Course Wind message body: %@", output);
                                ////NSLog(@"crc length: %d",messageCRC.length);
                            }
                            else
                            {
                                //NSLog(@"UNDEFINED MESSAGE!!!");
                            }
                            
                            
                            
                            //======
                            
                            
                            //crc received. This message is complete
                            expecting = 0;
                            needMore = 15;
                            [messageHeader setLength:0];
                            
                        }
                    }
                    
                    /*
                     len = [inputStream read:buffer maxLength:sizeof(buffer)];
                     if (len > 0) 
                     {
                     serverReturnedData = [NSMutableData dataWithBytes:buffer length:len];
                     dispatch_async(dispatch_get_main_queue(), ^
                     {
                     [self processData:serverReturnedData];
                     });
                     }
                     */
                    
                    
				}
			}
            
			break;
            
        case NSStreamEventHasSpaceAvailable: //4
            //NSLog(@"NSStreamEventHasSpaceAvailable");
            break;
            
			
		case NSStreamEventErrorOccurred: //8
        {
            
            if(aStream == inputStream)
            {
                ////NSLog(@"NSStreamEventErrorOccurred: Can not connect to the host!");
                /*
                if(reconnectTimer!=nil)
                {
                    [reconnectTimer invalidate];
                    reconnectTimer = nil;
                }
                
                reconnectTimer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(reconnect) userInfo:nil repeats:NO];
                [reconnectTimer fire];
                */
                
                NSError* error = [aStream streamError];
                NSString* errorMessage = [NSString stringWithFormat:@"%@ (Code = %d)",
                                          [error localizedDescription],
                                          [error code]];
                //NSLog(@"NSStreamEventErrorOccurred: Can not connect to the host!");
                
                
                noConnectionAlert = [[UIAlertView alloc] 
                                     initWithTitle:@"Stream Error" 
                                     message:errorMessage 
                                     delegate:self 
                                     cancelButtonTitle:@"Cancel" 
                                     otherButtonTitles:@"Reconnect", nil];
                
                [noConnectionAlert show];[noConnectionAlert release];
                 
                
            }
            
			break;
        }
			
		case NSStreamEventEndEncountered: //16
            
            if(aStream == inputStream)
            {
                
                
                UIAlertView *Alert = [[UIAlertView alloc] 
                                      initWithTitle:@"Stream Error" 
                                      message:@"Connection Terminated by the Server"
                                      delegate:nil         
                                      cancelButtonTitle:@"Continue" 
                                      otherButtonTitles:nil];
                [Alert show];[Alert release];
                
                [aStream close];
                [aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                [aStream release];
                aStream = nil;
                //NSLog(@"NSStreamEventEndEncountered: Connection terminated!");
            }
            
			
			break;
		default:
            break;
			//NSLog(@"Unknown event");
	}
    
}

-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if(alertView == noConnectionAlert)
    {
        if(buttonIndex == 0) //cancel button
        {
            
        }
        else if(buttonIndex == 1) //reconnect
        {
            [self reconnect];
        }
    }
}


-(void) reconnect
{
    //NSLog(@"reconnecting...");
    
    [self initNetWorkCommunicationWithIP:[[NSUserDefaults standardUserDefaults] stringForKey:@"IP"] Port:[[[NSUserDefaults standardUserDefaults] stringForKey:@"PORT"]intValue] ];
}


#pragma mark UIPopoverControllerDelegate methods

-(void) popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
    if(popoverController == pop)
    {
        //NSLog(@"pop dismiss detected!");
    }
    else if(popoverController == pop2)
    {
        //NSLog(@"pop2 dismiss detected");
    }
    
}

#pragma mark MKMapView delegate methods

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
    //showing annotations for race limit coordinates
    
    if([annotation isKindOfClass:[RaceLimitLocation class]])
    {
        
        NSString *identifier = @"RaceLimitIdentifier";
        
        MKAnnotationView* annotationView = (MKAnnotationView *)[myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        
       
        
        if (annotationView == nil) 
        {
            annotationView = [[MKAnnotationView alloc] 
                              initWithAnnotation:annotation 
                              reuseIdentifier:identifier];
            
            
        } 
        else 
        {
            
            annotationView.annotation = annotation;
        }
        
        annotationView.image = [UIImage imageNamed:@"dot.png"];
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        
        
        return annotationView;
    }
    
    
    //showing annotations for mark boats
    if([annotation isKindOfClass:[MarkBoatLocation class]])
    {
        NSString* identifier = @"MarkBoatIdentifier";
        
        MKAnnotationView* annotationView = (MKAnnotationView*)[myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        
        if(annotationView == nil)
        {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        }
        else
        {
            annotationView.annotation = annotation;
        }
        
        annotationView.image = [UIImage imageNamed:@"pinGray.png"];
        //annotationView.pinColor = MKPinAnnotationColorRed;
        
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        
        return  annotationView;
    }
    
    if([annotation isKindOfClass:[RaceBoatAnnotation class]])
    {
        NSString* identifier = @"raceBoatIdentifier";
        
        MKAnnotationView* annotationView = (MKAnnotationView*)[myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        
        if(annotationView == nil)
        {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        }
        else
        {
            annotationView.annotation = annotation;
        }
        
        //annotationView.image = [UIImage imageNamed:@"settings.png"];
        annotationView.image = [UIImage imageNamed:@"bluedot.png"];
        //annotationView.pinColor = MKPinAnnotationColorPurple;
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        annotationView.draggable = YES;
        
        return  annotationView;
    }
     
     
    return nil;
    
}

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
	//MKOverlayView* overlayView = nil;
	
   
    if(overlay == self.raceLimitPolygon)
	{
        
		
		if(self.raceLimitPolygonView == nil)
		{
			self.raceLimitPolygonView = [[[MKPolygonView alloc] initWithPolygon:self.raceLimitPolygon] autorelease];
			//self.routeLineView.fillColor = [UIColor whiteColor];
			self.raceLimitPolygonView.strokeColor = [UIColor whiteColor];
			self.raceLimitPolygonView.lineWidth = 1.0;
		}
        
        else
        {
            self.raceLimitPolygonView = nil;
        }
		
		//overlayView = self.raceLimitPolygonView;
        
        return self.raceLimitPolygonView;
		
	}
	
	return nil;
	
}

//update maptype based on uisegmentedcontrol games
-(void) updateMap:(MKMapType)mapType
{
    [self.myMapView setMapType:mapType];
    
}


-(void) dealloc
{
    [serverReturnedData release];
    [inputStream release];
    [outputStream release];
    [myMapView release];
    [raceLimitPolygon release];
    [raceLimitPolygonView release];
    
    [boatDictionary release];
    [regattaDictionary release];
    [raceDictionary release];
    
    [markAnnotationArray release];
    [raceLimitAnnotationArray release];
    [racingBoatsArray release];
    [raceBoatAnnotationDictionary release];
    
    [super dealloc];
}

@end
